package core;

import java.util.ArrayList;

import functions.Function;
import functions.FunctionIF;
import functions.PolynTerm;

public class LagrangeMethod extends InterpolatingMethod{

	private Point[] setOfPoints;
	@Override
	public Function run(Point[] points)
	{
		setOfPoints = points;
		ArrayList<Double> coeff = new ArrayList<Double>();
		for (Point p : points)
		{
			double x = p.getX();
			double y = p.getY();
			double denom = 1;

			for (Point p2 : points)
				if (p2.getX() != x)
					denom *= x - p2.getX();
			coeff.add(y / denom);
		}

		Function f = new Function();
		for (int k = 0; k < points.length; k++)
		{
			ArrayList<FunctionIF> product = new ArrayList<FunctionIF>();
			product.add(new PolynTerm(coeff.get(k), 0));
			for (int i = 0; i < points.length; i++)
				if (k != i)
				{
					product.add(getTerm(points[i].getX()));
				}
			f.addProductTerm(product);
		}
		return f;
	}

	private FunctionIF getTerm(double x)
	{
		Function f = new Function();
		ArrayList<FunctionIF> p = new ArrayList<FunctionIF>();
		p.add(new PolynTerm(1, 1));
		f.addProductTerm(p);

		ArrayList<FunctionIF> p1 = new ArrayList<FunctionIF>();
		p1.add(new PolynTerm(-x, 0));
		f.addProductTerm(p1);
		return f;
	}

	public double getErrorBound(Function f , double x){
		double coeff=1;
		FunctionIF diff = f;
		for(Point p : setOfPoints)
		{
			coeff*=(x-p.getX());
			diff=diff.diff();
		}
		coeff/=factorial(setOfPoints.length);
		double max = Double.MIN_VALUE;
		for(Point p : setOfPoints)
		{
			max = Math.max(max, diff.eval(p.getX()));
		}
		return coeff*max;
	}

	private double factorial(int num) {
		if(num==1)return 1;
		else return num*factorial(num-1);
	}
}
